//
//  HJNetworking.m
//  KaiChat
//
//  Created by lx on 2023/10/16.
//

#import "HJNetworking.h"
#import "HJAppInfo.h"
#import <MBProgressHUD.h>
#import "HJLoadingView.h"
#import "HJAlertController.h"
#import "HJCryptoTool.h"
#import "HJJSONRequestSerializer.h"
#import "HJJSONResponseSerializer.h"
#import "HJAWSS3Manager.h"


NSURLSessionDownloadTask * HJDownloadFileWithUrl(NSString *url,void (^progress)(CGFloat value), NSURL *(^destination)(void), void (^complete)(NSError * _Nullable error)) {
    
    NSString *localPath = destination().path;
    if ([[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
        complete(nil);
        return nil;
    }
    
    if (isEmptyString(url)) {
        complete([NSError errorWithCode:-10001 errorReason:@"url错误"]);
        return nil;
    }
    
    AFURLSessionManager *sessionManager = [[AFURLSessionManager alloc] init];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url.URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
    NSURLSessionDownloadTask *task = [sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        dispatch_async_main_queue(^{
            progress(downloadProgress.fractionCompleted);
        });
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return destination();
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        dispatch_async_main_queue(^{
            complete(error);
        });
    }];
    [task resume];
    return task;
}


@interface HJNetworking()<NSURLSessionDelegate>

@property (nonatomic, strong) NSArray *showErrorMessageApiArray;
@property (nonatomic, strong) NSArray *notHiddenLoadingMessageApiArray;
@property (nonatomic, strong) NSArray *logMessageApiArray;


@end

@implementation HJNetworking

static HJNetworking *_network = nil;

+ (HJNetworking *)shareNetwork {
    return [[HJNetworking alloc] init];
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_network == nil) {
            _network = [super allocWithZone:zone];
        }
    });
    return _network;
}

- (void)POST:(NSString *)url parameters:(id)parameters success:(void (^)(NSDictionary * _Nonnull, id _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure {
    [self dataTaskWithMethod:@"POST" urlString:url isJson:NO parameters:parameters success:^(id _Nullable responseObject) {
        [self handleResponseObject:responseObject url:url success:success failure:failure];
    } failure:^(NSError *error) {
        [self handleError:error url:url failure:failure];
    }];
}

- (void)POSTBodyJSON:(NSString *)url parameters:(nullable id)parameters success:(void (^__nullable)(NSDictionary *responseObject, id data))success failure:(void (^__nullable)(NSError *error))failure {
    [self dataTaskWithMethod:@"POST" urlString:url isJson:YES parameters:parameters success:^(id _Nullable responseObject) {
        [self handleResponseObject:responseObject url:url success:success failure:failure];
    } failure:^(NSError *error) {
        [self handleError:error url:url failure:failure];
    }];
}

- (void)GET:(NSString *)url parameters:(id)parameters success:(void (^)(NSDictionary * _Nonnull, id _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure {
    [self dataTaskWithMethod:@"GET" urlString:url isJson:YES parameters:parameters success:^(id _Nullable responseObject) {
        [self handleResponseObject:responseObject url:url success:success failure:failure];
    } failure:^(NSError *error) {
        [self handleError:error url:url failure:failure];
    }];
}

- (void)uploadImageWithObejctKey:(NSString *)obejctKey fileData:(NSData *)fileData progress:(nullable void (^)(int64_t totalUnitCount, int64_t completedUnitCount))uploadProgress success:(void (^)(NSString *url))success failure:(void (^)(NSError *error))failure {
    [HJAWSS3Manager.shareS3Manager updateWithData:fileData objectKey:obejctKey progressBlock:uploadProgress completionHandler:^(NSString * _Nullable url, NSError * _Nullable error) {
        if (error) {
            !failure ?: failure(error);
        } else {
            !success ?: success(url);
        }
    }];
    
//https://img-fs-dev.s3.ap-southeast-1.amazonaws.com/hj-global/bit-chat/1/240416/1/529315236798533/f59422c0c50e878456291fb16a4ab61e.jpg
    return;
    
        [HJNetworking.shareNetwork GET:API_uploadFile parameters:@{
            @"object_key": obejctKey
        } success:^(NSDictionary * _Nonnull responseObject, id  _Nonnull data) {
            NSString *urlString = data[@"url"];
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlString.URL];
            request.HTTPMethod = @"PUT";
            request.HTTPBody = fileData;
            [[getHTTPSessionManager() uploadTaskWithRequest:request fromData:nil progress:^(NSProgress * _Nonnull uploadProgress) {
                
            } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                if (error) {
                    !failure ?: failure(error);
                } else {
                    !success ?: success(getUrlPath(urlString));
                }
            }] resume];
        } failure:failure];
}

- (void)dataTaskWithMethod:(NSString *)method
                 urlString:(NSString *)urlString
                    isJson:(BOOL)isJson
                parameters:(nullable id)parameters
                   success:(void (^)(id  _Nullable responseObject))success failure:(void (^)(NSError * error))failure {
    
    NSDate *startDate = [NSDate date];
    NSString *url = [self getRequestUrlWithUrl:urlString];
    NSMutableDictionary *headers = [self addCommonHeaderWithUrl:urlString];
    
    AFHTTPSessionManager *sessionManager = isJson ? getBodyJsonHTTPSessionManager() : getHTTPSessionManager();
    NSURLSessionDataTask *dataTask = [sessionManager dataTaskWithHTTPMethod:method URLString:url.encodeUrl parameters:parameters headers:headers uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        //        if ([self.logMessageApiArray containsObject:urlString]) {
        TJDetailLog(@"method = %@, urlString = %@, parameters = %@, headers = %@ 耗时 = %.2f \n responseObject = %@", method, url, parameters, headers, [NSDate date].timeIntervalSince1970 - startDate.timeIntervalSince1970, responseObject);
        //        }
        
        if (success) {
            success(responseObject);
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        TJDetailLog(@"method = %@, urlString = %@, parameters = %@, headers = %@ 耗时 = %.2f \n error = %@", method, url, parameters, headers, [NSDate date].timeIntervalSince1970 - startDate.timeIntervalSince1970, error);
        if (failure) {
            failure(error);
        }
    }];
    [dataTask resume];
}

- (void)handleError:(NSError *)error url:(NSString *)url  failure:(void (^)(NSError * _Nonnull))failure {
    
    if (error.code != reCaptchaVerifyCode && HJTools.tool.currentHud) {
        MBProgressHUD *hud = HJTools.tool.currentHud;
        HJLoadingView *loadingView = (HJLoadingView *)hud.customView;
        if ([loadingView isKindOfClass:HJLoadingView.class]) {
            [loadingView stopAnimating];
            [hud hideAnimated:NO];
            HJTools.tool.currentHud = nil;
        }
    }
    
    if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == -1009) {
        [HJHUD showErrorMessage:@"Network error"];
        if (failure) {
            failure(error);
        }
        return;
    }
    
    NSDictionary *responseObject = [error getAFNOperationFailingURLResponseData];
    if (!responseObject) {
        if (failure) {
            failure(error);
        }
        return;
    }
    
    int resCode = [responseObject[@"code"] intValue];
    NSString *message = responseObject[@"msg"];
    
    //1301是被挤了, 1300和1302是登录过期
    if ((resCode >= 1300 && resCode < 1303) || resCode == 401) {
        [self tokenErrorWithCode:resCode];
        return;
    }
    
    if ([self.showErrorMessageApiArray containsObject:url]) {
        if (error.code == NSURLErrorTimedOut) {
            [HJHUD hiddenLoading];
            [HJHUD showErrorMessage:@"The request timed out"];
        } else {
            if (resCode != reCaptchaVerifyCode && !isEmptyString(message)) {
                [HJHUD showErrorMessage:message];
            }
        }
    }
    
    if (failure) {
        NSMutableDictionary *errorDict = @{}.mutableCopy;
        [errorDict setValue:message forKey:NSLocalizedFailureReasonErrorKey];
        [errorDict setValue:responseObject forKey:@"responseObject"];
        failure([NSError errorWithCode:resCode userInfo:errorDict]);
    }
}

- (void)tokenError {
    [self tokenErrorWithCode:1300];
}

- (void)tokenErrorWithCode:(int)code {
    if (!HJUserInfo.isLogin) {
        return;
    }
    [HJHUD hiddenLoading];
    [[NSNotificationCenter defaultCenter] postNotificationName:tokenErrorNotification object:nil userInfo:nil];
    HJUserInfo.isLogin = NO;
    HJUserInfo.token = nil;
    [HJAlertController alertInController:getMainController() title:nil message: code == 1301 ? @"Your account has been logged in from another device. Due to security reasons, this session has expired" : @"Login has expired, please log in again" left:nil right:^(HJAlertAction * _Nonnull action) {
        action.title = @"OK";
        action.titleColor = UIColor.tj_mainColor;
    }];
}

- (void)handleResponseObject:(NSDictionary *)responseObject url:(NSString *)url success:(void (^)(NSDictionary * _Nonnull, id _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure  {
    
    if (![responseObject isKindOfClass:NSDictionary.class]) return ;
    if (!responseObject.allKeys.count) return;
    int code = [responseObject[@"code"] intValue];
    
    if (![self.notHiddenLoadingMessageApiArray containsObject:url] && HJTools.tool.currentHud) {
        
        MBProgressHUD *hud = HJTools.tool.currentHud;
        HJLoadingView *loadingView = (HJLoadingView *)hud.customView;
        if ([loadingView isKindOfClass:HJLoadingView.class] && code != reCaptchaVerifyCode) {
            [loadingView stopAnimating];
            [hud hideAnimated:NO];
            HJTools.tool.currentHud = nil;
        }
    }
    
    
    if (code == 0 || code == 200) {
        if (success) {
            id data = responseObject[@"data"];
            
            if ([data isKindOfClass:NSNull.class]) {
                NSMutableDictionary *handleDict = [NSMutableDictionary dictionaryWithDictionary:responseObject];
                [handleDict removeObjectForKey:@"data"];
                success(handleDict, handleDict[@"data"]);
            } else {
                if ([data isKindOfClass:NSDictionary.class] && [data[@"list"] isKindOfClass:NSNull.class]) {
                    NSMutableDictionary *handleDict = [NSMutableDictionary dictionaryWithDictionary:responseObject];
                    [handleDict removeObjectForKey:@"data"];
                    success(handleDict, handleDict[@"data"]);
                } else {
                    success(responseObject, responseObject[@"data"]);
                }
            }
        }
        return;
    }
    
    NSString *message = responseObject[@"msg"];
    if ([self.showErrorMessageApiArray containsObject:url] && !isEmptyString(message)) {
        if (code != reCaptchaVerifyCode) {
            [HJHUD showErrorMessage:message];
        }
    }
    
    //1301是被挤了, 1300和1302是登录过期
    if ((code >= 1300 && code < 1303) || code == 401) {
        [self tokenErrorWithCode:code];
        return;
    }
    
    if (failure) {
        NSMutableDictionary *errorDict = @{}.mutableCopy;
        [errorDict setValue:message forKey:NSLocalizedFailureReasonErrorKey];
        [errorDict setValue:responseObject forKey:@"responseObject"];
        failure([NSError errorWithCode:code userInfo:errorDict]);
    }
    
}

- (NSString *)getRequestUrlWithUrl:(NSString *)url {
    if ([url containsString:@"http"]) {
        return url;
    }
    return [NSString stringWithFormat:@"%@%@", getBaseUrlString(), url];
}

- (BOOL)headerIsAddTokenWithUrl:(NSString *)url {
    if ([url isEqualToString:API_versionInfo] ||
        [url isEqualToString:API_outsideChain] ||
        [url isEqualToString:API_refreshToken]) {
        return NO;
    }
    if (HJUserInfo.isLogin && !isEmptyString(HJUserInfo.token)) {
        return YES;
    }
    return NO;
}

- (NSMutableDictionary *)addCommonHeaderWithUrl:(NSString *)url {
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    [dictionary setValue:getAppVersion() forKey:@"version-no"];
    [dictionary setValue:getAppChannel() forKey:@"channel"];
    [dictionary setValue:@"1" forKey:@"device_type"];
    if ([self headerIsAddTokenWithUrl:url]) {
        [dictionary setValue:HJUserInfo.token forKey:@"Authorization"];
    }
    if (HJUserInfo.enableGray) {
        [dictionary setValue:@"canary" forKey:@"containers"];
    }
    return dictionary;
}

- (NSArray *)showErrorMessageApiArray {
    if (!_showErrorMessageApiArray) {
        _showErrorMessageApiArray = @[
            API_login,
            API_loginV2,
            API_googleLogin,
            API_appleLogin,
            API_bindApple,
            API_bindGoogle,
            API_register,
            API_resetPassword,
            API_revoked,
            API_createGroup,
            API_postNotice,
            API_addGroupManager,
            API_removeGroupManager,
            API_exitGroup,
            API_transferGroup,
            API_disbandGroup,
            API_sendEmailCode,
            API_sendEmailCodeV2,
            API_agreeGroupInvite,
            API_modifyGroupInfo,
            API_KaiearmComplete,
            API_MPCWalletList,
            API_accountStatus,
            API_emailCodeLogin,
            API_emailVerify,
            API_emailVerifyV2,
            API_KaiearmComplete,
            API_setPassword,
            API_KaiPaySetPassword,
            API_bindingEmail,
            API_joinGroup,
            API_postNews,
            API_newsFollow
        ];
    }
    return _showErrorMessageApiArray;
}

- (NSArray *)logMessageApiArray {
    if (!_logMessageApiArray) {
        _logMessageApiArray = @[
            //            API_createGroup,
            //            API_postNotice,
            //            API_groupInfo,
            API_selfInfo,
            //            API_friendInfo,
            //            API_loginIpCheck,
            //            API_groupList,
            API_sendGroupMessage,
            API_sendSingleMessage,
            //            API_uploadFile,
            //            API_noticeDetail,
            //            API_searchUser,
            //            API_friendList,
            //            API_revokedCheck,
            //            API_applyAddFriend,
            //            API_applyList,
            //            API_offlineMessage,
            //            API_setBlacklist,
            //            API_reportTypeList,
            //            API_blacklistList,
            //            API_setBlacklist,
            //            API_report,
            API_userInfo,
            //            API_groupInviteCount,
            //            API_refreshToken,
            //            API_friendList,
            //            API_noticeDetail,
            //            API_unfreeze,
            API_login,
            //            API_versionInfo,
            //            API_sessionTop
        ];
    }
    return _logMessageApiArray;
}

- (NSArray *)notHiddenLoadingMessageApiArray {
    if (!_notHiddenLoadingMessageApiArray) {
        _notHiddenLoadingMessageApiArray = @[
            API_createGroup,
            API_uploadFile,
            API_inviteMembers,
            API_KaiPayIsSetPassword,
        ];
    }
    return _notHiddenLoadingMessageApiArray;
}

AFHTTPSessionManager *_bodyJsonSessionManager;
AFHTTPSessionManager * getBodyJsonHTTPSessionManager(void) {
    if (!_bodyJsonSessionManager) {
        _bodyJsonSessionManager = [AFHTTPSessionManager manager];
        _bodyJsonSessionManager.requestSerializer = [HJJSONRequestSerializer serializer];
        _bodyJsonSessionManager.responseSerializer = [HJJSONResponseSerializer serializer];
        _bodyJsonSessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", @"text/html", nil];
        [_bodyJsonSessionManager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
        _bodyJsonSessionManager.requestSerializer.timeoutInterval = 15.f;
        [_bodyJsonSessionManager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
        
    }
    return _bodyJsonSessionManager;
}

@end

